/*
 * Copyright (C) 2017 zhouyou(478319399@qq.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.shuyihui.rxhttp.interceptor

import com.shuyihui.rxhttp.utils.HttpLog
import com.shuyihui.rxhttp.utils.HttpUtil
import com.shuyihui.rxhttp.utils.Utils
import okhttp3.*
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import java.io.IOException
import java.io.UnsupportedEncodingException
import java.net.URLDecoder
import java.net.URLEncoder
import java.util.*

/**
 *
 * 描述：动态拦截器
 * 主要功能是针对参数：<br></br>
 * 1.可以获取到全局公共参数和局部参数，统一进行签名sign<br></br>
 * 2.可以自定义动态添加参数，类似时间戳timestamp是动态变化的，token（登录了才有），参数签名等<br></br>
 * 3.参数值是经过UTF-8编码的<br></br>
 * 4.默认提供询问是否动态签名（签名需要自定义），动态添加时间戳等<br></br>
 */
abstract class BaseDynamicInterceptor<out R : BaseDynamicInterceptor<R>?> : Interceptor {
    var httpUrl: HttpUrl? = null
        private set
    var isSign = false //是否需要签名
        private set
    var isTimeStamp = false //是否需要追加时间戳
        private set
    var isAccessToken = false //是否需要添加token
        private set

    fun sign(sign: Boolean): R {
        isSign = sign
        return this as R
    }

    fun timeStamp(timeStamp: Boolean): R {
        isTimeStamp = timeStamp
        return this as R
    }

    fun accessToken(accessToken: Boolean): R {
        isAccessToken = accessToken
        return this as R
    }

    @Throws(IOException::class)
    override fun intercept(chain: Interceptor.Chain): Response {
        var request: Request = chain.request()
        if (request.method == "GET") {
            httpUrl = parseUrl(request.url.toUrl().toString()).toHttpUrlOrNull()
            request = addGetParamsSign(request)
        } else if (request.method == "POST") {
            httpUrl = request.url
            request = addPostParamsSign(request)
        }
        return chain.proceed(request)
    }

    //get 添加签名和公共动态参数
    @Throws(UnsupportedEncodingException::class)
    private fun addGetParamsSign(request: Request): Request {
        var request = request
        var httpUrl = request.url
        val newBuilder: HttpUrl.Builder = httpUrl.newBuilder()

        //获取原有的参数
        val nameSet = httpUrl.queryParameterNames
        val nameList = ArrayList<String>()
        nameList.addAll(nameSet)
        val oldparams = TreeMap<String, String>()
        for (i in nameList.indices) {
            val value =
                if (httpUrl.queryParameterValues(nameList[i]) != null && httpUrl.queryParameterValues(
                        nameList[i]
                    ).isNotEmpty()
                ) {
                    httpUrl.queryParameterValues(nameList[i])[0]!!
                } else ""
            oldparams[nameList[i]] = value
        }
        val nameKeys = listOf(nameList).toString()
        //拼装新的参数
        val newParams = dynamic(oldparams)
        Utils.checkNotNull(newParams, "newParams==null")
        for ((key, value) in newParams) {
            val urlValue = URLEncoder.encode(value, HttpUtil.UTF8.name())
            //原来的URl: https://xxx.xxx.xxx/app/chairdressing/skinAnalyzePower/skinTestResult?appId=10101
            if (!nameKeys.contains(key)) { //避免重复添加
                newBuilder.addQueryParameter(key, urlValue)
            }
        }
        httpUrl = newBuilder.build()
        request = request.newBuilder().url(httpUrl).build()
        return request
    }

    //post 添加签名和公共动态参数
    @Throws(UnsupportedEncodingException::class)
    private fun addPostParamsSign(request: Request): Request {
        var request = request
        if (request.body is FormBody) {
            val bodyBuilder = FormBody.Builder()
            var formBody = request.body as FormBody?

            //原有的参数
            val oldparams = TreeMap<String, String>()
            for (i in 0 until formBody!!.size) {
                oldparams[formBody.encodedName(i)] = formBody.encodedValue(i)
            }

            //拼装新的参数
            val newParams = dynamic(oldparams)
            Utils.checkNotNull(newParams, "newParams==null")
            //Logc.i("======post请求参数===========");
            for ((key, value1) in newParams) {
                val value = URLDecoder.decode(value1, HttpUtil.UTF8.name())
                bodyBuilder.addEncoded(key, value)
                //                Logc.i(entry.getKey() + " -> " + value);
            }
            val url = HttpUtil.createUrlFromParams(
                httpUrl!!.toUrl().toString(), newParams
            )
            HttpLog.i(url)
            formBody = bodyBuilder.build()
            request = request.newBuilder().post(formBody).build()
        } else if (request.body is MultipartBody) {
            var multipartBody = request.body as MultipartBody?
            val bodyBuilder: MultipartBody.Builder = MultipartBody.Builder().setType(MultipartBody.FORM)
            val oldparts: List<MultipartBody.Part> = multipartBody!!.parts

            //拼装新的参数
            val newparts: MutableList<MultipartBody.Part> = ArrayList<MultipartBody.Part>()
            newparts.addAll(oldparts)
            val oldparams = TreeMap<String, String>()
            val newParams = dynamic(oldparams)
            for ((key, value) in newParams) {
                val part: MultipartBody.Part = MultipartBody.Part.createFormData(key, value)
                newparts.add(part)
            }
            for (part in newparts) {
                bodyBuilder.addPart(part)
            }
            multipartBody = bodyBuilder.build()
            request = request.newBuilder().post(multipartBody).build()
        }
        return request
    }

    //解析前：https://xxx.xxx.xxx/app/chairdressing/skinAnalyzePower/skinTestResult?appId=10101
    //解析后：https://xxx.xxx.xxx/app/chairdressing/skinAnalyzePower/skinTestResult
    private fun parseUrl(url: String): String {
        var url = url
        if ("" != url && url.contains("?")) { // 如果URL不是空字符串
            url = url.substring(0, url.indexOf('?'))
        }
        return url
    }

    /**
     * 动态处理参数
     *
     * @param dynamicMap
     * @return 返回新的参数集合
     */
    abstract fun dynamic(dynamicMap: TreeMap<String, String>?): TreeMap<String, String>
}